<?php

namespace Dddxiu;

use Dddxiu\traits\Singleton;

/**
 * 漏斗
 */
class Funnel
{
    use Singleton;

    // 输入数据
    private $input = [];

    // 默认的规则列表
    private $default_rules = [];

    // 需要检查的
    private $valid_rules = [];

    // 错误列表
    private $errors = [];

    // 规则全解析/中断继续校验
    private $interrupt = false;

    /**
     * load本地规则
     */
    public function __construct()
    {
        $this->loadRules();
    }

    /**
     * 加载本地的规则
     */
    protected function loadRules()
    {
        $base   = __DIR__ . DIRECTORY_SEPARATOR . 'rules';
        $handle = opendir($base);
        while (false !== ($file = readdir($handle))) {
            $class = strstr($file, '.php', true);
            if (empty($class)) {
                continue;
            }

            $class = __NAMESPACE__ . '\\rules\\' . $class;
            if (class_exists($class)) {
                $this->register($class::F, $class);
            }
        }
        closedir($handle);
    }

    /**
     * 注册自定义规则
     *
     * @param string $f 标志
     * @param callable|string $call 校对器
     * @return void
     */
    protected function register($f, $call)
    {
        $this->default_rules[$f] = $call;
    }

    /**
     * 输入数据
     *
     * @param array $input 输入字段
     * @return void
     */
    protected function input($input)
    {
        $this->input = $input;
    }

    /**
     * 规则
     *
     * @param array $rules 校验规则
     * @return void
     */
    protected function rules($rules)
    {
        $this->valid_rules = $rules;
    }

    /**
     * 是否中断校验
     * @param boolean $interrupt
     */
    protected function setInterrupt($interrupt)
    {
        $this->interrupt = $interrupt;
    }

    /**
     * 执行过滤
     * @param array $input
     * @param array $rules
     * @param boolean $interrupt
     * @return boolean
     * @throws \Exception
     */
    protected function standing($input, $rules, $interrupt = false)
    {
        if (empty($input)) {
            return false;
        }
        if (empty($rules)) {
            return true;
        }

        $this->input       = $input;
        $this->valid_rules = $rules;
        $this->interrupt   = $interrupt;

        Layer::meta($this->input, $this->default_rules, $this, $this->interrupt);
        foreach ($this->valid_rules as $field => $rule) {
            $abort = Layer::filter($field, $rule);
            if ($abort && !$this->interrupt) {
                return false;
            }
        }
        return true;
    }

    /**
     * 记录错误
     * @param string $field 字段名
     * @param mixed $value 字段值
     * @param string $rule 名称
     * @param mixed $rule_value 规则值
     * @return void
     */
    private function errorRecord($field, $value, $rule, $rule_value)
    {
        $this->errors[$field][$rule] = [$value, $rule_value];
    }

    /**
     * 错误结果
     * @return array
     */
    private function getErrors()
    {
        return $this->errors;
    }
}